<template>
  <div ref="SelectBoxRef" class="input_number_container">
    <!-- 减号按钮 -->
    <div
      class="step_button minus"
      :class="{ disabled: isMinReached }"
      @click="decrement"
    >
      <svg viewBox="0 0 24 24" width="16" height="16">
        <path d="M19 13H5v-2h14v2z" fill="currentColor"/>
      </svg>
    </div>

    <!-- 输入框区域 -->
    <div class="input_area">
      <input
        ref="inputRef"
        @input="listenInput"
        @blur="handleBlur"
        v-model="displayValue"
        :placeholder="placeholder"
        type="text"
        inputmode="decimal"
      />
    </div>

    <!-- 加号按钮 -->
    <div
      class="step_button plus"
      :class="{ disabled: isMaxReached }"
      @click="increment"
    >
      <svg viewBox="0 0 24 24" width="16" height="16">
        <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" fill="currentColor"/>
      </svg>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch } from "vue";

defineOptions({
  name: "InputNumber",
  inheritAttrs: false,
});

const props = defineProps({
  placeholder: {
    type: String,
    default: "请输入"
  },
  // 精度 - 控制小数点后几位
  precision: {
    type: Number,
    default: 2,
    validator: (value) => value >= 0 && value <= 10
  },
  // 每次点击加减的步长
  step: {
    type: Number,
    default: 1,
    validator: (value) => value > 0
  },
  // 最小值
  min: {
    type: Number,
    default: -Infinity
  },
  // 最大值
  max: {
    type: Number,
    default: Infinity
  },
  // 是否显示步进按钮
  showControls: {
    type: Boolean,
    default: true
  }
});

const emit = defineEmits(['update:modelValue', 'change', 'blur']);

// 与父组件绑定值
const modelValue = defineModel();

const inputRef = ref(null);
const displayValue = ref('');

// 计算属性：是否达到最小值
const isMinReached = computed(() => {
  return Number(modelValue.value) <= props.min;
});

// 计算属性：是否达到最大值
const isMaxReached = computed(() => {
  return Number(modelValue.value) >= props.max;
});

// 监听外部值变化
watch(modelValue, (newVal) => {
  if (newVal === null || newVal === undefined) {
    displayValue.value = '';
    return;
  }

  const numValue = Number(newVal);
  if (isNaN(numValue)) {
    displayValue.value = '';
    return;
  }

  // 格式化显示值
  displayValue.value = formatNumber(numValue);
}, { immediate: true });

// 格式化数字
function formatNumber(value) {
  if (value === '' || value === null || value === undefined) return '';

  const num = Number(value);
  if (isNaN(num)) return '';

  // 处理精度
  let formatted;
  if (props.precision === 0) {
    formatted = Math.round(num).toString();
  } else {
    formatted = num.toFixed(props.precision);
    // 去除末尾的0和小数点（如1.20 → 1.2）
    formatted = formatted.replace(/(\.\d*?[1-9])0+$/, '$1').replace(/\.$/, '');
  }

  return formatted;
}

// 输入处理
function listenInput(e) {
  const value = e.target.value;

  // 允许空值
  if (value === '') {
    modelValue.value = null;
    return;
  }

  // 过滤非法字符
  const filteredValue = value
    .replace(/[^0-9.-]/g, '') // 只允许数字、小数点和负号
    .replace(/(\..*)\./g, '$1') // 只允许一个小数点
    .replace(/(^-*)–/g, '$1') // 替换长破折号为短破折号
    .replace(/(^-*)-/g, '$1') // 只允许一个负号且在开头
    .replace(/^(-?)0+(?=\d)/, '$1'); // 去除前导零

  // 如果过滤后的值与原始值不同，更新输入框
  if (filteredValue !== value) {
    e.target.value = filteredValue;
    displayValue.value = filteredValue;
  }

  // 如果值为空或只有一个负号，设置为null
  if (filteredValue === '' || filteredValue === '-') {
    modelValue.value = null;
    return;
  }

  const numValue = Number(filteredValue);
  if (!isNaN(numValue)) {
    // 限制在min/max范围内
    let clampedValue = Math.min(Math.max(numValue, props.min), props.max);

    // 处理精度
    if (props.precision >= 0) {
      const factor = Math.pow(10, props.precision);
      clampedValue = Math.round(clampedValue * factor) / factor;
    }

    // 如果值被限制，更新显示
    if (clampedValue !== numValue) {
      displayValue.value = formatNumber(clampedValue);
    }

    modelValue.value = clampedValue;
  }
}

// 失焦处理
function handleBlur() {
  // 如果当前值为空，设置为最小值或0
  if (displayValue.value === '') {
    modelValue.value = props.min >= 0 ? props.min : 0;
  }
  emit('blur', modelValue.value);
}

// 增加数值
function increment() {
  if (isMaxReached.value) return;

  const current = modelValue.value === null || modelValue.value === ''
    ? props.min
    : Number(modelValue.value);

  let newValue = current + props.step;

  // 处理精度
  if (props.precision > 0) {
    const factor = Math.pow(10, props.precision);
    newValue = Math.round(newValue * factor) / factor;
  }

  // 限制最大值
  newValue = Math.min(newValue, props.max);

  modelValue.value = newValue;
  emit('change', newValue);
}

// 减少数值
function decrement() {
  if (isMinReached.value) return;

  const current = modelValue.value === null || modelValue.value === ''
    ? props.min
    : Number(modelValue.value);

  let newValue = current - props.step;

  // 处理精度
  if (props.precision > 0) {
    const factor = Math.pow(10, props.precision);
    newValue = Math.round(newValue * factor) / factor;
  }

  // 限制最小值
  newValue = Math.max(newValue, props.min);

  modelValue.value = newValue;
  emit('change', newValue);
}

// 聚焦输入框
function focus() {
  inputRef.value?.focus();
}

// 暴露方法
defineExpose({
  focus
});
</script>

<style lang="scss" scoped>
.input_number_container {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  background: #F0F2F7;
  border-radius: 8px;
  overflow: hidden;
}

.input_area {
  flex: 1;
  height: 100%;

  input {
    width: 100%;
    height: 100%;
    border: none;
    outline: none;
    background: none;
    box-shadow: none;
    margin: 0;
    padding: 6px 12px;
    font-family: inherit;
    font-weight: inherit;
    color: inherit;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    text-align: center;

    &::-webkit-inner-spin-button,
    &::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }
  }
}

.step_button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 100%;
  cursor: pointer;
  color: #666;
  transition: all 0.2s;
  user-select: none;

  &:hover {
    background-color: #d0d0d0;
  }

  &.minus {
    border-top-left-radius: 8px;
    border-bottom-left-radius: 8px;
  }

  &.plus {
    border-top-right-radius: 8px;
    border-bottom-right-radius: 8px;
  }

  &.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: #ccc;
  }
}

.font_placeholder {
  font-size: 14px;
  font-weight: normal;
  line-height: 20px;
  letter-spacing: normal;
  color: #808690;
}

.font_value {
  color: #1C1E24;
}
</style>
